home *** CD-ROM | disk | FTP | other *** search
/ PC World Interactive 7 / PC World Interactive 7.iso / program / cprog.EXE / C-DERSI4.C < prev    next >
C/C++ Source or Header  |  1996-06-25  |  11KB  |  315 lines

  1.  
  2.                                     Lesson 3
  3.  
  4.                                Arrays and Pointers.
  5.  
  6.    You can allocate space for an array of elements at compile time with fixed
  7.    dimension sizes of any data type, even functions and structs.
  8.    So these are legal array definitions:
  9.  
  10.   char name[30];                   /* An array of 30 signed characters. */
  11.   char *strings[50];               /* 50 pointers to strings. */
  12.   unsigned long int *(*func)()[20];/* An array of pointers to functions which
  13. */
  14.                                    /* return pointers to unsigned long ints. */
  15.  
  16.    You can declare a pointer to point at any type of data element, and as in
  17.    the array situation above functions and structs are included.
  18.  
  19. struct ship
  20. {
  21.   char name[30];
  22.   double displacement;                           /* in grammes */
  23.   float length_of_water_line;                    /* in meters */
  24.   unsigned short int number_of_passengers;
  25.   unsigned short int number_of_crew;
  26.   };
  27.  
  28.    So using the ship concept from Lesson 2 you can declare a pointer to point
  29.    at one of the ship structs in an array.
  30.  
  31. struct ship *vessel_p;
  32.  
  33.    Note the use of the suffix "_p".
  34.    This is my way of reminding myself that the variable is a pointer.
  35.  
  36. struct ship fleet[5];     /* This allocates enough storage for 5 ships' info.
  37. */
  38.  
  39.    Now lets set the pointer to point at the first vessel in the fleet.
  40.  
  41.   vessel_p = fleet;
  42.  
  43.    This pointer can be made to point at other ships in the fleet by
  44.    incrementing it or doing additive arithmetic on it:
  45.  
  46.   vessel_p++;             /* point a the next ship in the fleet array. */
  47.   vessel_p = fleet + 3;
  48.  
  49.    Also we can find out the index of the ship in the fleet at which we are
  50.    pointing:
  51.  
  52.   i = vessel_p - fleet;
  53.  
  54.    It is also legal to find out the separation of two pointers pointing at
  55.    elements in an array:
  56.  
  57.   d = vessel_p - another_vessel_p; /* This gives the separation in elements. */
  58.  
  59.    So summarising, pointers may be, incremented, decremented, and subtracted
  60.    one from another or have a constant subtracted from them. Any other
  61.    mathematical operation is meaningless and not allowed.
  62.  
  63.    Assembler programmers should note that while the pointer variables contain a
  64.    byte machine address, when the arithmetic is done using pointers the
  65. compiler
  66.    also issues either a multiply or a divide as well as the add or subtract
  67.    instruction so that the result is ALWAYS expressed in elements rather than
  68.    bytes. Have a go and write yourself a trivial little program, and have a
  69.    look at the compiler ouput code. Lesson 1 told you how!
  70.  
  71.    When using a pointer to reference a structure we have to use a "pointer
  72.    offset" operator in order to access the member of the struct we require:
  73.  
  74.   vessel_p = fleet;
  75.  
  76.   vessel_p->name = "Queen Mary";
  77.   vessel_p->displacement = 97500000000.0;
  78.   vessel_p->length_of_water_line = 750.0
  79.   vessel_p->number_of_passengers = 3575;
  80.   vessel_p->number_of_crew = 4592;
  81.  
  82.    Remember:
  83.  
  84.        It's a "." when accessing a struct which is in storage declared in
  85.        the program.
  86.  
  87.        It's a "->" when accessing a struct at which a pointer is pointing.
  88.  
  89.   Initialisation of arrays.
  90.  
  91.    'C' has the facility to initialise variables in a program script.
  92.  
  93.    Some examples:
  94.  
  95.   char *qbf = "The quick brown fox jumped over the lazy dogs back";
  96.  
  97.   int tic_tac_toe[3][3] =
  98.   {
  99.     { 1, 2, 3 },
  100.     { 4, 5, 6 },
  101.     { 7, 8, 9 }
  102.     };
  103.  
  104.   struct ship fleet[2] =
  105.   {
  106.     { "Queen Elizabeth",  97500000000.0, 750.0, 3575, 4592 },
  107.     {      "Queen Mary", 115000000000.0, 875.0, 4500, 5500 }
  108.     };
  109.  
  110.    Take a careful note of where the commas and semi-colons go ( and don't go )!
  111.  
  112.    Initialised Tables of Indeterminate Length.
  113.  
  114.    One nice feature 'C' offers is that it is able to calculate
  115.    the amount of storage required for a table by 'looking' at the number
  116.    of initialisers.
  117.  
  118. char *verse[] =
  119. {
  120.   "On top of the Crumpetty Tree",
  121.   "The Quangle Wangle sat,",
  122.   "But his face you could not see,",
  123.   "On account of his Beaver Hat.",
  124.   "For his Hat was a hundred and two feet wide.",
  125.   "With ribbons and bibbons on every side,",
  126.   "And bells, and buttons, and loops, and lace,",
  127.   "So that nobody ever could see the face",
  128.   "Of the Quangle Wangle Quee."
  129.   NULL
  130.   };
  131.  
  132.    Note the * character in the definition line. This means that we are going
  133.    to make an array of pointers to variables of type char. As there is no
  134.    number between the [ ] characters the compiler calculates it for us.
  135.    With this kind of set-up it is nice and easy to add extra information
  136.    to the table as program development proceeds. The compiler will calculate
  137.    the new dimension for you. The point to remember is that the program has to
  138.    know - from the contents of the table - that it has come to the end of the
  139.    table! So you have to make a special entry which CANNOT under any
  140.    circumstances be a real data element. We usually use NULL for this.
  141.    The other way is to calculate the size of the table by using the sizeof
  142.          operator - Note that although use of sizeof looks like a function call
  143.          it is in fact an intrinsic operator of the language. The result is
  144.          available at compile time. So one can say:-
  145.  
  146.         #define SIZE_OF_VERSE sizeof verse
  147.  
  148.    There is one final initialised data type, the enum. It is a fairly recent
  149.    addition to the language.
  150.  
  151.   enum spectrum { red, orange, yellow, green, blue, indigo, violet } colour;
  152.  
  153.    In this construct the first symbol is given the value of 0 and for each
  154.    following symbol the value is incremented. It is however possible to assign
  155.    specific values to the symbols like this:
  156.  
  157.   enum tub
  158.   { anorexic = 65,
  159.     slim = 70,
  160.     normal = 80,
  161.     fat = 95,
  162.     obese = 135
  163.     };
  164.  
  165.    Some compilers are bright enough to detect that it is an error if an
  166.    attempt is made to assign a value to an enum variable which is not in
  167.    the list of symbols, on the other hand many are not. Take care! In
  168.    practice there is little difference between the enum language construct
  169.    and a number of define statements except perhaps aesthetics. Here is
  170.    another trivial program which demonstrates the use of enum and a
  171.    pre-initialised array.
  172.  
  173. #include <stdio.h>
  174.  
  175. enum spectrum { red, orange, yellow, green, blue, indigo, violet } colour;
  176.  
  177. char *rainbow[] = { "red", "orange", "yellow", "green",
  178.                     "blue", "indigo", "violet" };
  179.  
  180. main()
  181. {
  182.   for ( colour = red; colour <= violet; colour++ )
  183.   {
  184.     printf ( "%s ", rainbow[colour]);
  185.     }
  186.   printf ( "\n" );
  187.   }
  188.  
  189.    The output of which is ( not surprisingly ):
  190.  
  191. red orange yellow green blue indigo violet
  192.  
  193.    One quite advanced use of initialised arrays and pointers is the jump or
  194.    dispatch table. This is a efficient use of pointers and provides a very much
  195.    better ( In my opinion ) method of controlling program flow than a maze
  196.    of case or ( heaven forbid ) if ( ... ) goto statements.
  197.  
  198.    Please cut out this program, read and compile it.
  199.    ------------------------------------------------------------------------
  200.  
  201. char *ident = "@(#) tellme.c - An example of using a pointer to a function.";
  202.  
  203. #include <stdio.h>
  204. #include <math.h>
  205. #include <sys/errno.h>
  206.  
  207. /*
  208. These declarations are not in fact needed as they are all declared extern in
  209. math.h. However if you were to use routines which are not in a library and
  210. therefore not declared in a '.h' file you should declare them. Remember you
  211. MUST declare external routines which return a type other than the int type.
  212.  
  213. extern double  sin ();
  214. extern double  cos ();
  215. extern double  tan ();
  216. extern double atof ();
  217. */
  218.  
  219. struct table_entry
  220. {
  221.   char *name;                        /* The address of the character string. */
  222.   double (*function)();   /* The address of the entry point of the function. */
  223.   };
  224.  
  225. typedef struct table_entry TABLE;
  226.  
  227. double help ( tp )
  228. TABLE *tp;
  229. { printf ( "Choose one of these functions:- " );
  230.   fflush ( stdout );
  231.   for ( ; tp -> name; tp++ ) printf ( "%s ", tp -> name );
  232.   printf ( "\nRemember the input is expressed in Radians\n" );
  233.   exit ( 0 );
  234.   return ( 0.0 );  /* Needed to keep some nit-picking dumb compilers happy! */
  235.   }
  236.  
  237. /*
  238.  * This is the array of pointers to the strings and function entry points.
  239.  * Is is initialised at linking time. You may add as many functions as you
  240.  * like in here PROVIDED you declare them to be extern, either in some .h
  241.  * file or explicitly.
  242.  */
  243.  
  244. TABLE interpretation_table [ ] =
  245. {
  246.   { "sin",  sin  },
  247.   { "tan",  tan  },
  248.   { "cos",  cos  },
  249.   { "help", help },
  250.   {  NULL,  NULL }               /* To flag the end of the table. */
  251.   };
  252.  
  253. char *output_format = { "\n %s %s = %g\n" };
  254. extern int errno;
  255. extern void perror();
  256.  
  257. main( argc, argv )
  258. int argc;
  259. char **argv;
  260. {
  261.   TABLE *tp;
  262.   double x, answer;
  263.  
  264.   if ( argc > 3 )
  265.   {
  266.     errno = E2BIG;
  267.     perror ( "tellme" );
  268.     exit ( -1 );
  269.     }
  270.  
  271.   for (;;)                  /* This is the way to set up a continuous loop. */
  272.   {
  273.     for ( tp = interpretation_table;
  274.           ( tp -> name && strcmp ( tp -> name, argv[1] ));
  275.           tp++
  276.     )  ;                      /* Note use of empty for loop to position tp. */
  277.  
  278.     if ( tp -> function == help ) (*tp -> function )( interpretation_table );
  279.     if ( tp -> name == NULL )
  280.     {
  281.       printf ( "Function %s not implemented yet\n", argv[1] );
  282.       exit ( 1 );
  283.       }
  284.     break;                     /* Leave the loop. */
  285.     }
  286.  
  287.   x = atof ( argv[2] );        /* Convert the character string to a double. */
  288.   answer = ( *tp -> function )( x );/* Execute the desired function.        */
  289.   printf ( output_format,      /* Pointer to printf()'s format string.      */
  290.            argv[1],            /* Pointer to the name of the function.      */
  291.            argv[2],            /* Pointer to the input number ascii string. */
  292.            answer              /* Value ( in double floating point binary ) */
  293.            );
  294.   }
  295.  
  296. Copyright notice:-
  297.  
  298. (c) 1993 Christopher Sawtell.
  299.  
  300. I assert the right to be known as the author, and owner of the
  301. intellectual property rights of all the files in this material,
  302. except for the quoted examples which have their individual
  303. copyright notices. Permission is granted for onward copying,
  304. but not modification, of this course and its use for personal
  305. study only, provided all the copyright notices are left in the
  306. text and are printed in full on any subsequent paper reproduction.
  307.  
  308. --
  309.  +----------------------------------------------------------------------+
  310.  | NAME   Christopher Sawtell                                           |
  311.  | SMAIL  215 Ollivier's Road, Linwood, Christchurch, 8001. New Zealand.|
  312.  | EMAIL  chris@gerty.equinox.gen.nz                                    |
  313.  | PHONE  +64-3-389-3200   ( gmt +13 - your discretion is requested )   |
  314.  +----------------------------------------------------------------------+
  315.